<?php
/**
 * 路由
 */

namespace core;

use core\App;
use core\Debug;
use core\AppException;
use core\cache\CacheManager;

class Route
{
    private static $routes = [];         // 存储路由规则
    private static $controller;          // 当前控制器
    private static $action;              // 当前操作
    private static $params = [];         // 路由参数

    // 路由组配置
    private static $groupStack = [];     // 路由组栈
    // 中间件集合
    private static $middleware = [];     // 中间件配置

    // 路由缓存键
    private static $cacheKey = 'route_cache';

    /**
     * 定义路由组
     * @param array $options 路由组选项（prefix, middleware等）
     * @param callable $callback 路由组回调函数
     */
    public static function group(array $options, callable $callback)
    {
        // 记录当前路由组配置
        array_push(self::$groupStack, $options);

        // 执行回调函数
        $callback();

        // 回调执行完毕，弹出当前路由组配置
        array_pop(self::$groupStack);
    }

    /**
     * 注册GET路由
     * @param string $uri 路由URI
     * @param mixed $action 路由处理动作
     * @param array $middleware 中间件
     */
    public static function get($uri, $action, $middleware = [])
    {
        self::registerRoute('GET', $uri, $action, $middleware);
    }

    /**
     * 注册POST路由
     * @param string $uri 路由URI
     * @param mixed $action 路由处理动作
     * @param array $middleware 中间件
     */
    public static function post($uri, $action, $middleware = [])
    {
        self::registerRoute('POST', $uri, $action, $middleware);
    }

    /**
     * 注册路由
     * @param string $method 请求方法
     * @param string $uri 路由URI
     * @param string $controller 控制器
     * @param array $middleware 中间件
     */
    private static function registerRoute($method, $uri, $controller, $middleware = [])
    {
        // 清除路由缓存
        self::clearRouteCache();

        // 应用路由组前缀
        $prefix = '';
        $groupMiddleware = [];
        foreach (self::$groupStack as $group) {
            if (isset($group['prefix'])) {
                $prefix .= trim($group['prefix'], '/') . '/';
            }
            if (isset($group['middleware']) && is_array($group['middleware'])) {
                $groupMiddleware = array_merge($groupMiddleware, $group['middleware']);
            }
        }

        // 合并路由组中间件和路由自身中间件
        $middleware = array_merge($groupMiddleware, $middleware);

        $uri = trim($uri, '/');
        if (!empty($prefix)) {
            $uri = $prefix . $uri;
        }

        // 存储路由
        self::$routes[strtoupper($method)][$uri] = $controller;

        // 存储中间件
        if (!empty($middleware)) {
            self::$middleware[strtoupper($method)][$uri] = $middleware;
        }
    }

    /**
     * 分发请求
     */
    public function dispatch()
    {
        // 尝试从缓存获取路由
        $cachedRoutes = CacheManager::get(self::$cacheKey);

        if ($cachedRoutes) {
            self::$routes = $cachedRoutes;
            Debug::log('路由已从缓存加载');
        } else {
            // 缓存不存在，加载路由文件
            $routeFile = ROUTE_PATH . 'route.php';
            if (file_exists($routeFile)) {
                require_once $routeFile;

                // 缓存路由
                CacheManager::set(self::$cacheKey, self::$routes, 3600);
                Debug::log('路由已缓存');
            } else {
                throw new AppException("路由文件不存在: {$routeFile}", 500);
            }
        }

        // 获取请求方法和URI
        $method = $_SERVER['REQUEST_METHOD'];
        $uri = trim($_SERVER['REQUEST_URI'], '/');

        // 去除查询字符串
        if (strpos($uri, '?') !== false) {
            $uri = substr($uri, 0, strpos($uri, '?'));
        }

        // 尝试直接匹配路由
        if (isset(self::$routes[$method][$uri])) {
            $controllerInfo = self::$routes[$method][$uri];
            $this->executeController($controllerInfo, $method, $uri);
            return;
        }

        // 尝试匹配带参数的路由
        $this->matchParamRoute($method, $uri);

        // 如果没有匹配到路由，抛出404异常
        throw new AppException("未找到路由: {$method} {$uri}", 404);
    }

    /**
     * 匹配带参数的路由
     * @param string $method 请求方法
     * @param string $uri 请求URI
     */
    private function matchParamRoute($method, $uri)
    {
        if (!isset(self::$routes[$method])) {
            return;
        }

        $uriSegments = explode('/', $uri);

        foreach (self::$routes[$method] as $routeUri => $controllerInfo) {
            $routeSegments = explode('/', $routeUri);

            // 如果段数不同，直接跳过
            if (count($uriSegments) != count($routeSegments)) {
                continue;
            }

            $params = [];
            $match = true;

            for ($i = 0; $i < count($routeSegments); $i++) {
                // 检查是否为参数段
                if (preg_match('/^{(.+)}$/', $routeSegments[$i], $matches)) {
                    $paramName = $matches[1];
                    $params[$paramName] = $uriSegments[$i];
                } elseif ($routeSegments[$i] != $uriSegments[$i]) {
                    $match = false;
                    break;
                }
            }

            if ($match) {
                self::$params = $params;
                $this->executeController($controllerInfo, $method, $routeUri);
                return;
            }
        }
    }

    /**
     * 执行控制器
     * @param mixed $controllerInfo 控制器信息（字符串或数组）
     * @param string $method 请求方法
     * @param string $uri 路由URI
     */
    private function executeController($controllerInfo, $method, $uri)
    {
        // 解析控制器和方法
        if (is_array($controllerInfo)) {
            if (count($controllerInfo) != 2) {
                throw new AppException("控制器格式错误: ".json_encode($controllerInfo), 500);
            }
            $controllerName = $controllerInfo[0];
            $actionName = $controllerInfo[1];
        } else {
            $parts = explode('@', $controllerInfo);
            if (count($parts) != 2) {
                throw new AppException("控制器格式错误: {$controllerInfo}", 500);
            }
            $controllerName = $parts[0];
            $actionName = $parts[1];
        }
    
        // 从URI获取应用名称
        $appName = 'index'; // 默认应用
        $uriSegments = explode('/', $uri);
        if (isset($uriSegments[0]) && !empty($uriSegments[0])) {
            // 检查是否是已定义的应用
            $apps = ['admin', 'api', 'index', 'open'];
            if (in_array($uriSegments[0], $apps)) {
                $appName = $uriSegments[0];
            }
        }
    
        // 构建完整的控制器类名（包含命名空间）
        $fullControllerName = 'app\\' . $appName . '\\controller\\' . $controllerName;
    
        // 设置当前控制器和方法
        self::$controller = $controllerName;
        self::$action = $actionName;
    
        // 检查控制器类是否存在
        if (!class_exists($fullControllerName)) {
            throw new AppException("控制器不存在: {$fullControllerName}", 404);
        }
    
        // 实例化控制器
        $controller = new $fullControllerName();

        // 检查方法是否存在
        if (!method_exists($controller, $actionName)) {
            throw new AppException("方法不存在: {$actionName}", 404);
        }

        // 获取中间件
        $middleware = [];
        if (isset(self::$middleware[$method][$uri])) {
            $middleware = self::$middleware[$method][$uri];
        }

        // 执行中间件
        $request = (object)array_merge($_GET, $_POST, ['params' => self::$params]);
        $this->executeMiddleware($middleware, $request, function($request) use ($controller, $actionName) {
            // 调用初始化方法
            if (method_exists($controller, 'initialize')) {
                $controller->initialize();
            }

            // 调用前置操作
            if (method_exists($controller, '__before')) {
                $controller->__before();
            }

            // 调用控制器方法
            // call_user_func_array([$controller, $actionName], array_values(self::$params));
            // 改为使用runAction方法，确保经过中间件
            $controller->runAction($actionName, array_values(self::$params));

            // 调用后置操作
            if (method_exists($controller, '__after')) {
                $controller->__after();
            }
            return true;
        });
    }

    /**
     * 执行中间件
     * @param array $middleware 中间件数组
     * @param object $request 请求对象
     * @param callable $next 下一个处理函数
     * @return mixed
     */
    private function executeMiddleware(array $middleware, $request, callable $next)
    {
        if (empty($middleware)) {
            return $next($request);
        }

        $firstMiddleware = array_shift($middleware);
        $middlewareClass = 'app\\common\\middleware\\' . $firstMiddleware;

        if (class_exists($middlewareClass)) {
            $middlewareObj = new $middlewareClass();
            if (method_exists($middlewareObj, 'handle')) {
                return $middlewareObj->handle($request, function($request) use ($middleware, $next) {
                    return $this->executeMiddleware($middleware, $request, $next);
                });
            }
        }

        // 如果中间件不存在，直接执行下一个
        return $this->executeMiddleware($middleware, $request, $next);
    }

    /**
     * 获取当前控制器
     * @return string
     */
    public static function getController()
    {
        return self::$controller;
    }

    /**
     * 获取当前操作
     * @return string
     */
    public static function getAction()
    {
        return self::$action;
    }

    // 添加获取当前应用名称的方法
    /**
     * 获取当前应用名称
     * @return string
     */
    public static function getAppName()
    {
        static $appName = null;
        if ($appName === null) {
            $uri = trim($_SERVER['REQUEST_URI'], '/');
            // 去除查询字符串
            if (strpos($uri, '?') !== false) {
                $uri = substr($uri, 0, strpos($uri, '?'));
            }
            
            $uriSegments = explode('/', $uri);
            $appName = 'index'; // 默认应用
            
            if (isset($uriSegments[0]) && !empty($uriSegments[0])) {
                // 检查是否是已定义的应用
                $apps = ['admin', 'api', 'index', 'open'];
                if (in_array($uriSegments[0], $apps)) {
                    $appName = $uriSegments[0];
                }
            }
        }
        return $appName;
    }

    /**
     * 获取路由参数
     * @param string $key 参数名
     * @param mixed $default 默认值
     * @return mixed
     */
    public static function getParam($key, $default = null)
    {
        return isset(self::$params[$key]) ? self::$params[$key] : $default;
    }

    /**
     * 清除路由缓存
     */
    public static function clearRouteCache()
    {
        CacheManager::delete(self::$cacheKey);
    }
}